using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Space
{
    public class MenuItem
    {
        public string Name { get; set; }
        public string Command { get; set; }
        public object Argument { get; set; }
        public Texture2D Texture { get; set; }

        public delegate bool IsEnabled();
    }
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class MenuComponent : Microsoft.Xna.Framework.DrawableGameComponent
    {
        List<List<MenuItem>> items = new List<List<MenuItem>>();

        List<int> highs = new List<int>();
        int listHigh = 0;

        public MenuComponent(Game game)
            : base(game)
        {
            // TODO: Construct any child components here
            
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here
            Visible = false;
            base.Initialize();
        }

        protected override void LoadContent()
        {
            List<MenuItem> shipList = new List<MenuItem>();
            List<MenuItem> planetList = new List<MenuItem>();
            items.Add(shipList);
            items.Add(planetList);
            items.Add(new List<MenuItem>());

            for (int i = 0; i < items.Count; i++)
                highs.Add(0);

            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            IDataInput input = Game.Services.GetService<IDataInput>();

            IGameActions gact = Game.Services.GetService<IGameActions>();

            if (gact.ProgramStage == Stage.Game)
            {
                if (input.IsButtonPressed(Buttons.LeftShoulder, this))
                    Visible = !Visible;
                //Visible = input.LeftTrigger > 0.5f;

                if (Visible)
                    input.Lock(this);
                else
                    input.Unlock(this);

                if (Visible)
                {
                    if (input.IsKeyClicked(Keys.Down) || input.IsButtonPressed(Buttons.LeftThumbstickDown, this))
                    {
                        Navigate(1);
                    }
                    else if (input.IsKeyClicked(Keys.Up) || input.IsButtonPressed(Buttons.LeftThumbstickUp, this))
                    {
                        Navigate(-1);
                    } if (input.IsKeyClicked(Keys.Left) || input.IsButtonPressed(Buttons.LeftTrigger, this))
                    {
                        NavigateHorizontal(1);
                    }
                    else if (input.IsKeyClicked(Keys.Right) || input.IsButtonPressed(Buttons.RightTrigger, this))
                    {
                        NavigateHorizontal(-1);
                    }
                    else if (input.IsKeyClicked(Keys.Enter) || input.IsButtonPressed(Buttons.A, this))
                    {
                        IGameActions gameActions = (IGameActions)Game.Services.GetService(typeof(IGameActions));
                        gameActions.ProcessMenuItem(items[listHigh][highs[listHigh]]);
                    }
                }

                IData data = Game.Services.GetService<IData>();

                SolarSystem solar = data.SolarSystems.Where(s => (s.Position - data.MainPlayer.FlagShip.Position).Length() < s.Radius).OrderBy(s => (s.Position - data.MainPlayer.FlagShip.Position).LengthSquared()).FirstOrDefault();

                items.ForEach(s=>s.Clear());

                List<MenuItem> shipList = items[0];

                shipList.Add(new MenuItem
                {
                    Name = "Add Corvette",
                    Command = "buy_ship",
                    Argument = "corvette",
                    Texture = Game.Content.Load<Texture2D>("textures/buy_corvette")
                });
                //shipList.Add(new MenuItem
                //{
                //    Name = "Add Colony Ship",
                //    Command = "buy_ship",
                //    Argument = "colony",
                //    Texture = Game.Content.Load<Texture2D>("textures/buy_corvette")
                //});
                shipList.Add(new MenuItem
                {
                    Name = "Build Destroyer",
                    Command = "buy_ship",
                    Argument = "destroyer",
                    Texture = Game.Content.Load<Texture2D>("textures/buy_destroyer")
                });
                shipList.Add(new MenuItem
                {
                    Name = "Build Cruiser",
                    Command = "buy_ship",
                    Argument = "cruiser",
                    Texture = Game.Content.Load<Texture2D>("textures/buy_cruiser")
                });
                shipList.Add(new MenuItem
                {
                    Name = "Build Battleship",
                    Command = "buy_ship",
                    Argument = "battleship",
                    Texture = Game.Content.Load<Texture2D>("textures/buy_battleship")
                });
                shipList.Add(new MenuItem
                {
                    Name = "Build Carrier",
                    Command = "buy_ship",
                    Argument = "carrier",
                    Texture = Game.Content.Load<Texture2D>("textures/buy_carrier")
                });

                List<MenuItem> planetList = items[1];

                if (solar != null)
                {
                    Planet p = null;
                    foreach (SolarSystem s in data.SolarSystems)
                    {
                        p = s.Planets.Find(planet => planet.Player.Neutral && (planet.Position - data.MainPlayer.FlagShip.Position).Length() <= C.ColonizeDistance);
                        if (p != null) break;
                    }

                    if (p != null)
                    {
                        if (!data.MainPlayer.MainFleet.Exists(ship => ship.Action == "colonize" && ship.ActionTarget == p))
                            planetList.Add(new MenuItem
                            {
                                Name = "Colonize Planets",
                                Command = "colonize",
                                Argument = p,
                                Texture = Game.Content.Load<Texture2D>("textures/colonize")
                            });
                    }
                    planetList.Add(new MenuItem
                    {
                        Name = "Build Gun",
                        Command = "build",
                        Argument = "gun",
                        Texture = Game.Content.Load<Texture2D>("textures/build_gun")
                    });

                    MenuItem tradeItem = CreateBuildingMenuItem(solar, data, "trade");
                    if(tradeItem!=null)
                    planetList.Add(tradeItem);
                }

                //planetList.Add(new MenuItem
                //{
                //    Name = "",
                //    Command = "",
                //    Argument = "",
                //    Texture = Game.Content.Load<Texture2D>("textures/")
                //});

                //items.Add(new MenuItem
                //{
                //    Name = "Add Frigate",
                //    Command = "buy_ship",
                //    Argument = "frigate",
                //    Texture = Game.Content.Load<Texture2D>("textures/buy_corvette")
                //});

                List<MenuItem> pirateMenu = items[2];
                pirateMenu.Add(new MenuItem
                {
                    Name = "Build Privateer",
                    Command = "buy_pirate",
                    Argument = "pirate",
                    Texture = Game.Content.Load<Texture2D>("textures/buy_corvette")
                });

                for (int i = 0; i < highs.Count; i++)
                {
                    if (highs[i] >= items[i].Count) highs[i] = items[i].Count - 1;
                    if (highs[i] < 0) highs[i] = 0;
                }
            }
            base.Update(gameTime);
        }

        MenuItem CreateBuildingMenuItem(SolarSystem solar, IData data, string category)
        {
            Building existingBuilding = solar.Buildings.Find(b => b.Player == data.MainPlayer && b.Category == category);

            int level = 1;
            if (existingBuilding != null)
            {
                if (existingBuilding.Level == Building.MaxLevel(category)) return null;
                else
                    level = existingBuilding.Level + 1;
            }

            switch (category)
            {
                case "trade":
                    return new MenuItem
                    {
                        Name = level==1?"Build":"Upgrade"+" Trade Center",
                        Command = "build",
                        Argument = "trade",
                        Texture = Game.Content.Load<Texture2D>("textures/build_trade"+level),
                    };
                default:
                    throw new Exception("Unknown type: " + category);
            }
        }

        public void Navigate(int i)
        {
            if (items[listHigh].Count == 0) return;

            if (i < 0)
            {
                highs[listHigh] += i;
                while (highs[listHigh] < 0) highs[listHigh] += items[listHigh].Count;
            }
            else
                highs[listHigh] = (highs[listHigh] + i) % items[listHigh].Count;
        }

        public void NavigateHorizontal(int i)
        {
            if (i < 0)
            {
                listHigh += i;
                while (listHigh < 0) listHigh += items.Count;
            }
            else
                listHigh = (listHigh + i) % items.Count;
        }

        public override void Draw(GameTime gameTime)
        {
            SpriteBatch spriteBatch = Game.Services.GetService<IGraphics>().SpriteBatch;

            if (Visible)
            {
                spriteBatch.Begin();
                Rectangle position = new Rectangle(20, 20, 120, 50);
                for (int i = 0; i < items[listHigh].Count; i++)
                {
                    MenuItem item = items[listHigh][i];
                    spriteBatch.Draw(item.Texture, position, i == highs[listHigh] ? Color.White : Color.Gray);
                    position.Y += 50;
                }
                spriteBatch.End();
            }
            base.Draw(gameTime);
        }
    }
}
